About
Giant Spectrum is an interactive audio-visual wall piece that displays a live, moving spectral representation of the sounds it hears. Much like light, sound is comprised of many different frequencies, and different sounds contain changing frequencies with varying amplitudes. As sounds occur, the piece shows these changing parts in real time as a moving spectral display. Any sound present in the room appears on the display.
The piece is made of aluminum, polycarbonate, and custom electronics. It was constructed over a four month period from December 2015 to March 2016.
Giant Spectrum was exhibited in "Sweet Gongs Vibrating" at the San Diego Art Institute, and in the WaveCave gallery at California Institute of the Arts during 2016.
San Diego City Beat had this to say in an article featuring Giant Spectrum:
The standout of the show, however, has to be Cooper Baker's "Giant Spectrum," a nearly four-foot aluminum and plastic light sculpture that responds to the noise of the room. Stand next to it silently and it will pick up the viewer's slightest movements. Make a bunch of noise and the plastic, vacuformed lights start to sporadically flash. (... full text)
SDAI Photos
CalArts Photos
Video
Build Photos
Circuitry
Source Code
//------------------------------------------------------------------------------
// Spectral display with MSGEQ7 and shift registers for Arduino
//
// spectrum.ino
//
// Created by Cooper Baker on 12/13/15.
// Copyright (c) 2016 Cooper Baker. All rights reserved.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// includes
//------------------------------------------------------------------------------
// Include xcode.h for syntax coloring
#include "xcode.h"
#include "EEPROM.h"
#include <math.h>
//------------------------------------------------------------------------------
// definitions
//------------------------------------------------------------------------------
// shift register pins
#define SCLK 12
#define RCLK 11
#define SOUT 10
#define OE 9
// msgeq7 pins
#define STROBE 8
#define RESET 7
#define EQ_DATA 0
// switch pin
#define MODE 4
// switch debounce time
#define DEBOUNCE_MSEC 40
// led refresh rate
#define REFRESH_MSEC 20
// range averaging coefficients
#define MAX_AVG_COEFF 0.9991
#define MIN_AVG_COEFF 0.99999
// threshold coefficients
#define MAX_THRESH 0.666
#define MIN_THRESH 0.05
// meter decay decrements
#define DECAY_FAST 0.026
#define DECAY_SLOW 0.005
// pwm values for brightness
#define BRIGHT 0
#define DIM 192
// eeprom address
#define EEPROM_MODE_ADDR 0
// clipping macro
#define clip( x, l, h ) (x) < (l) ? (l) : ( (x) > (h) ? (h) : (x) )
//------------------------------------------------------------------------------
// prototypes
//------------------------------------------------------------------------------
void setup ( void );
void loop ( void );
void signature ( void );
void upDown ( void );
inline void updateLeds ( void );
inline void readEq ( void );
inline void calculateValues ( void );
inline void setMode ( byte index );
inline void allOff ( void );
//------------------------------------------------------------------------------
// variables
//------------------------------------------------------------------------------
// signature array
byte sig[] =
{
B00000000, B00000000, B00000000, B00000000, // space
B00000000, B00000000, B00000000, B00000000, // space
B00111110, B00100010, B00100010, B00000000, // C
B00111110, B00100010, B00111110, B00000000, // O
B00111110, B00100010, B00111110, B00000000, // O
B00111110, B00101000, B00111000, B00000000, // P
B00111110, B00101010, B00101010, B00000000, // E
B00111110, B00101000, B00110110, B00000000, // R
B00000000, B00000000, B00000000, B00000000, // space
B00111110, B00101010, B00110110, B00000000, // B
B00111110, B00101000, B00111110, B00000000, // A
B00111110, B00001000, B00110110, B00000000, // K
B00111110, B00101010, B00101010, B00000000, // E
B00111110, B00101000, B00110110, B00000000, // R
B00000000, B00000000, B00000000, B00000000, // space
B00101110, B00101010, B00111010, B00000000, // 2
B00111110, B00100010, B00111110, B00000000, // O
B00100010, B00111110, B00000010, B00000000, // 1
B00111110, B00101010, B00101110, B00000000, // 6
B00000000, B00000000, B00000000, B00000000, // space
B00000000, B00000000, B00000000, B00000000 // space
};
// numeral patterns
byte num[] =
{
B00000000, B00000000, B00100010, B00111110, B00000010, B00000000, B00000000, // 1
B00000000, B00000000, B00101110, B00101010, B00111010, B00000000, B00000000, // 2
B00000000, B00000000, B00101010, B00101010, B00111110, B00000000, B00000000, // 3
B00000000, B00000000, B00111000, B00111110, B00001000, B00000000, B00000000 // 4
};
// bit patterns for led 'dots'
// dot[ 0 ] = all off, dot[ 8 ] = max
byte dot[ 9 ] = { B00000000,
B00000001,
B00000010,
B00000100,
B00001000,
B00010000,
B00100000,
B01000000,
B10000000 };
// values from adc
float raw[ 7 ] = { 0, 0, 0, 0, 0, 0, 0 };
// spectrum values between 0 and 1
float spec[ 7 ] = { 0, 0, 0, 0, 0, 0, 0 };
// remapped bands of spectrum values
float band[ 7 ] = { 0, 0, 0, 0, 0, 0, 0 };
// max / min averages per band
float max[ 7 ] = { 1, 1, 1, 1, 1, 1, 1 };
float min[ 7 ] = { 0, 0, 0, 0, 0, 0, 0 };
// max / min peak detection
float maxPeak[ 7 ][ 3 ] = { { 0 } };
float minPeak[ 7 ][ 3 ] = { { 0 } };
// bytes for shift registers
byte out[ 7 ] = { 0, 0, 0, 0, 0, 0, 0 };
// intermediate averaging coefficients
float maxInCoeff;
float minInCoeff;
// transfer funciton array
float xfer[ 100 ] = { 0 };
// mode switch variables
byte mode;
byte swMode;
byte swModePrev;
byte swModeState;
// timer variables
unsigned long msec;
unsigned long nextMsec;
unsigned long swModeMsec;
// decay decrement
float decayDec;
//------------------------------------------------------------------------------
// signature - scrolls sig[] array across the display
//------------------------------------------------------------------------------
void signature( void )
{
byte i;
// scroll through signature array
for( i = 0 ; i < 77 ; i++ )
{
// disable latch
digitalWrite( RCLK, LOW );
// move bytes to shift registers
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 6 ] );
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 5 ] );
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 4 ] );
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 3 ] );
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 2 ] );
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 1 ] );
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 0 ] );
// enable latch
digitalWrite( RCLK, HIGH );
// wait
delay( 275 );
}
}
//------------------------------------------------------------------------------
// upDown - moves a horizontal bar up and down the display
//------------------------------------------------------------------------------
void upDown( void )
{
byte i;
byte j;
for( i = 1 ; i < 8 ; i++ )
{
for( j = 0 ; j < 7 ; j++ )
{
out[ j ] = dot[ i ];
}
updateLeds();
delay( 152);
}
for( i = 6 ; i > 0 ; i-- )
{
for( j = 0 ; j < 7 ; j++)
{
out[ j ] = dot[ i ];
}
updateLeds();
delay( 152 );
}
}
//------------------------------------------------------------------------------
// updateLeds - shifts bits from out[] array to led shift registers
//------------------------------------------------------------------------------
inline void updateLeds( void )
{
// disable latch
digitalWrite( RCLK, LOW );
// move bytes to shift registers
shiftOut( SOUT, SCLK, MSBFIRST, out[ 6 ] );
shiftOut( SOUT, SCLK, MSBFIRST, out[ 5 ] );
shiftOut( SOUT, SCLK, MSBFIRST, out[ 4 ] );
shiftOut( SOUT, SCLK, MSBFIRST, out[ 3 ] );
shiftOut( SOUT, SCLK, MSBFIRST, out[ 2 ] );
shiftOut( SOUT, SCLK, MSBFIRST, out[ 1 ] );
shiftOut( SOUT, SCLK, MSBFIRST, out[ 0 ] );
// enable latch
digitalWrite( RCLK, HIGH );
}
//------------------------------------------------------------------------------
// readEq - reads analog values from the msgeq7 chip
//------------------------------------------------------------------------------
inline void readEq( void )
{
byte i;
// reset msgeq7 multiplexor
digitalWrite ( RESET, HIGH );
delayMicroseconds( 10 );
digitalWrite ( RESET, LOW );
digitalWrite ( STROBE, HIGH );
delayMicroseconds( 80 );
// read the eq values
for( i = 0 ; i < 7 ; i++ )
{
digitalWrite ( STROBE, LOW );
delayMicroseconds( 40 );
// lowpass the raw values
raw[ i ] = analogRead( EQ_DATA ) * 0.9 + raw[ i ] * 0.1;
digitalWrite ( STROBE, HIGH );
delayMicroseconds( 40 );
}
}
//------------------------------------------------------------------------------
// calculateValues - calculates spectrum values using data in raw[] array
//------------------------------------------------------------------------------
inline void calculateValues( void )
{
int i;
float x;
float minIn;
float maxIn;
// iterate through the raw bands
for( i = 0 ; i < 7 ; i++ )
{
// scale raw band value between 0 and 1
x = raw[ i ] / 1024.0;
// minimum averaging
//----------------------------------------------------------------------
// look at last three values
minPeak[ i ][ 2 ] = minPeak[ i ][ 1 ];
minPeak[ i ][ 1 ] = minPeak[ i ][ 0 ];
minPeak[ i ][ 0 ] = x;
// find valleys
if( ( minPeak[ i ][ 0 ] > minPeak[ i ][ 1 ] ) && ( minPeak[ i ][ 1 ] < minPeak[ i ][ 2 ] ) )
{
minIn = minPeak[ i ][ 1 ];
}
else
{
minIn = min[ i ];
}
// calculate weighted min average ( lowpass filter )
min[ i ] = min[ i ] * MIN_AVG_COEFF + minIn * minInCoeff;
// discard values below min
x -= min[ i ];
// normalize
x *= 1.0 / ( 1.0 - min[ i ] );
// clip between 0 and 1
x = clip( x, 0, 1 );
// maximum averaging
//----------------------------------------------------------------------
// look at last three values
maxPeak[ i ][ 2 ] = maxPeak[ i ][ 1 ];
maxPeak[ i ][ 1 ] = maxPeak[ i ][ 0 ];
maxPeak[ i ][ 0 ] = x;
// find peaks
if( ( maxPeak[ i ][ 0 ] < maxPeak[ i ][ 1 ] ) && ( maxPeak[ i ][ 1 ] > maxPeak[ i ][ 2 ] ) )
{
maxIn = maxPeak[ i ][ 1 ];
}
else
{
maxIn = max[ i ];
}
// update max peak average
max[ i ] = maxIn > max[ i ] ? maxIn : max[ i ];
// calculate weighted max average ( lowpass filter )
max[ i ] = max[ i ] * MAX_AVG_COEFF + maxIn * maxInCoeff;
// set minimum max average to MAX_THRESH
max[ i ] = max[ i ] < MAX_THRESH ? MAX_THRESH : max[ i ];
// normalize to average range
x /= max[ i ] - min[ i ];
// scaling
//----------------------------------------------------------------------
// drop values below threshold
x -= MIN_THRESH;
x *= 1.0 / ( 1.0 - MIN_THRESH );
// scale a little larger
x *= 1.2;
x -= MIN_THRESH;
// constrain between 0 and 1
x = clip( x, 0, 1 );
// output transfer function
x = xfer[ int( x * 99 ) ];
// update value for display
spec[ i ] = x > spec[ i ] ? x : spec[ i ];
}
// remap middle 5 input bands onto 7 output bands
band[ 0 ] = spec[ 1 ] * 0.950000 + spec[ 2 ] * 0.050000;
band[ 1 ] = spec[ 1 ] * 0.285714 + spec[ 2 ] * 0.714286;
band[ 2 ] = spec[ 2 ] * 0.714286 + spec[ 3 ] * 0.285714;
band[ 3 ] = spec[ 2 ] * 0.250000 + spec[ 3 ] * 0.500000 + spec[ 4 ] * 0.25;
band[ 4 ] = spec[ 3 ] * 0.285714 + spec[ 4 ] * 0.714286;
band[ 5 ] = spec[ 4 ] * 0.714286 + spec[ 5 ] * 0.285714;
band[ 6 ] = spec[ 5 ] * 0.900000 + spec[ 4 ] * 0.100000;
// create output values for display
for( i = 0 ; i < 7 ; i++ )
{
// constrain between 0 and 1
x = clip( band[ i ], 0, 1 );
// use remapped values for display
out[ i ] = dot[ ( int )( x * 8.0 ) ];
// update decay filter
spec[ i ] -= decayDec;
}
}
//------------------------------------------------------------------------------
// setMode - sets display mode based on index ( 1 - 4 )
//------------------------------------------------------------------------------
inline void setMode( byte index )
{
switch( mode )
{
// fast, bright
case 1 : decayDec = DECAY_FAST;
analogWrite( OE, BRIGHT );
break;
// fast, dim
case 2 : decayDec = DECAY_FAST;
analogWrite( OE, DIM );
break;
// slow, bright
case 3 : decayDec = DECAY_SLOW;
analogWrite( OE, BRIGHT );
break;
// slow, dim
case 4 : decayDec = DECAY_SLOW;
analogWrite( OE, DIM );
break;
}
}
//------------------------------------------------------------------------------
// numeral - displays a numeral based on value ( 1 - 4 )
//------------------------------------------------------------------------------
inline void numeral( byte value )
{
allOff();
value = value - 1;
out[ 6 ] = num[ 6 + value * 7 ];
out[ 5 ] = num[ 5 + value * 7 ];
out[ 4 ] = num[ 4 + value * 7 ];
out[ 3 ] = num[ 3 + value * 7 ];
out[ 2 ] = num[ 2 + value * 7 ];
out[ 1 ] = num[ 1 + value * 7 ];
out[ 0 ] = num[ 0 + value * 7 ];
updateLeds();
delay( 500 );
allOff();
}
//------------------------------------------------------------------------------
// allOff - turns off all leds
//------------------------------------------------------------------------------
inline void allOff( void )
{
byte i;
for( i = 0 ; i < 7 ; i++ )
{
out [ i ] = 0;
}
updateLeds();
}
//------------------------------------------------------------------------------
// setup - initializes arduino board
//------------------------------------------------------------------------------
void setup( void )
{
// disable leds
pinMode( OE, OUTPUT );
analogWrite( OE, 255 );
// configure pins
pinMode( SCLK, OUTPUT );
pinMode( RCLK, OUTPUT );
pinMode( SOUT, OUTPUT );
pinMode( OE, OUTPUT );
pinMode( STROBE, OUTPUT );
pinMode( RESET, OUTPUT );
pinMode( EQ_DATA, INPUT );
pinMode( MODE, INPUT );
// configure 5v analog reference for msgeq7
analogReference( DEFAULT );
// initialize variables
msec = 0;
nextMsec = 0;
swMode = 0;
swModePrev = 0;
swModeMsec = 0;
swModeState = 0;
maxInCoeff = 1.0 - MAX_AVG_COEFF;
minInCoeff = 1.0 - MIN_AVG_COEFF;
// read mode from memory
mode = EEPROM.read( EEPROM_MODE_ADDR );
// calculate transfer function
float x;
for( byte i = 0 ; i < 100 ; i++ )
{
x = float( i ) / 100.0;
xfer[ i ] = cos( 3.141592 * pow( x, 0.5 ) ) * -0.5 + 0.5;
}
// set mode
setMode( mode );
// initial display
allOff();
upDown();
signature();
}
//------------------------------------------------------------------------------
// loop - the main program loop
//------------------------------------------------------------------------------
void loop( void )
{
// read values from msgeq7
readEq();
// timer
//--------------------------------------------------------------------------
// store current millisecond value
msec = millis();
// spectrum
//--------------------------------------------------------------------------
// refresh spectrum if enough milliseconds have elapsed
if( ( long )( msec - nextMsec ) >= 0 )
{
// calculate next update time
nextMsec = msec + REFRESH_MSEC;
// update the spectrum
calculateValues();
updateLeds();
}
// switch
//--------------------------------------------------------------------------
// store switch state
swMode = digitalRead( MODE );
// if switch state has changed
if( swMode != swModePrev )
{
// store current millisecond value
swModeMsec = millis();
}
// if the debounce interval has elapsed
if( ( millis() - swModeMsec ) > DEBOUNCE_MSEC )
{
// if stitch state has changed
if( swMode != swModeState )
{
// store switch state
swModeState = swMode;
// if switch is on
if( swModeState == HIGH )
{
// increment and wrap mode value
mode++;
mode > 4 ? mode = 1 : mode;
// set the mode
setMode( mode );
// display the mode
numeral( mode );
// save mode value to memory
EEPROM.write( EEPROM_MODE_ADDR, mode );
}
}
}
// store swtich state
swModePrev = swMode;
}
//------------------------------------------------------------------------------
// EOF
//------------------------------------------------------------------------------
// Spectral display with MSGEQ7 and shift registers for Arduino
//
// spectrum.ino
//
// Created by Cooper Baker on 12/13/15.
// Copyright (c) 2016 Cooper Baker. All rights reserved.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// includes
//------------------------------------------------------------------------------
// Include xcode.h for syntax coloring
#include "xcode.h"
#include "EEPROM.h"
#include <math.h>
//------------------------------------------------------------------------------
// definitions
//------------------------------------------------------------------------------
// shift register pins
#define SCLK 12
#define RCLK 11
#define SOUT 10
#define OE 9
// msgeq7 pins
#define STROBE 8
#define RESET 7
#define EQ_DATA 0
// switch pin
#define MODE 4
// switch debounce time
#define DEBOUNCE_MSEC 40
// led refresh rate
#define REFRESH_MSEC 20
// range averaging coefficients
#define MAX_AVG_COEFF 0.9991
#define MIN_AVG_COEFF 0.99999
// threshold coefficients
#define MAX_THRESH 0.666
#define MIN_THRESH 0.05
// meter decay decrements
#define DECAY_FAST 0.026
#define DECAY_SLOW 0.005
// pwm values for brightness
#define BRIGHT 0
#define DIM 192
// eeprom address
#define EEPROM_MODE_ADDR 0
// clipping macro
#define clip( x, l, h ) (x) < (l) ? (l) : ( (x) > (h) ? (h) : (x) )
//------------------------------------------------------------------------------
// prototypes
//------------------------------------------------------------------------------
void setup ( void );
void loop ( void );
void signature ( void );
void upDown ( void );
inline void updateLeds ( void );
inline void readEq ( void );
inline void calculateValues ( void );
inline void setMode ( byte index );
inline void allOff ( void );
//------------------------------------------------------------------------------
// variables
//------------------------------------------------------------------------------
// signature array
byte sig[] =
{
B00000000, B00000000, B00000000, B00000000, // space
B00000000, B00000000, B00000000, B00000000, // space
B00111110, B00100010, B00100010, B00000000, // C
B00111110, B00100010, B00111110, B00000000, // O
B00111110, B00100010, B00111110, B00000000, // O
B00111110, B00101000, B00111000, B00000000, // P
B00111110, B00101010, B00101010, B00000000, // E
B00111110, B00101000, B00110110, B00000000, // R
B00000000, B00000000, B00000000, B00000000, // space
B00111110, B00101010, B00110110, B00000000, // B
B00111110, B00101000, B00111110, B00000000, // A
B00111110, B00001000, B00110110, B00000000, // K
B00111110, B00101010, B00101010, B00000000, // E
B00111110, B00101000, B00110110, B00000000, // R
B00000000, B00000000, B00000000, B00000000, // space
B00101110, B00101010, B00111010, B00000000, // 2
B00111110, B00100010, B00111110, B00000000, // O
B00100010, B00111110, B00000010, B00000000, // 1
B00111110, B00101010, B00101110, B00000000, // 6
B00000000, B00000000, B00000000, B00000000, // space
B00000000, B00000000, B00000000, B00000000 // space
};
// numeral patterns
byte num[] =
{
B00000000, B00000000, B00100010, B00111110, B00000010, B00000000, B00000000, // 1
B00000000, B00000000, B00101110, B00101010, B00111010, B00000000, B00000000, // 2
B00000000, B00000000, B00101010, B00101010, B00111110, B00000000, B00000000, // 3
B00000000, B00000000, B00111000, B00111110, B00001000, B00000000, B00000000 // 4
};
// bit patterns for led 'dots'
// dot[ 0 ] = all off, dot[ 8 ] = max
byte dot[ 9 ] = { B00000000,
B00000001,
B00000010,
B00000100,
B00001000,
B00010000,
B00100000,
B01000000,
B10000000 };
// values from adc
float raw[ 7 ] = { 0, 0, 0, 0, 0, 0, 0 };
// spectrum values between 0 and 1
float spec[ 7 ] = { 0, 0, 0, 0, 0, 0, 0 };
// remapped bands of spectrum values
float band[ 7 ] = { 0, 0, 0, 0, 0, 0, 0 };
// max / min averages per band
float max[ 7 ] = { 1, 1, 1, 1, 1, 1, 1 };
float min[ 7 ] = { 0, 0, 0, 0, 0, 0, 0 };
// max / min peak detection
float maxPeak[ 7 ][ 3 ] = { { 0 } };
float minPeak[ 7 ][ 3 ] = { { 0 } };
// bytes for shift registers
byte out[ 7 ] = { 0, 0, 0, 0, 0, 0, 0 };
// intermediate averaging coefficients
float maxInCoeff;
float minInCoeff;
// transfer funciton array
float xfer[ 100 ] = { 0 };
// mode switch variables
byte mode;
byte swMode;
byte swModePrev;
byte swModeState;
// timer variables
unsigned long msec;
unsigned long nextMsec;
unsigned long swModeMsec;
// decay decrement
float decayDec;
//------------------------------------------------------------------------------
// signature - scrolls sig[] array across the display
//------------------------------------------------------------------------------
void signature( void )
{
byte i;
// scroll through signature array
for( i = 0 ; i < 77 ; i++ )
{
// disable latch
digitalWrite( RCLK, LOW );
// move bytes to shift registers
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 6 ] );
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 5 ] );
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 4 ] );
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 3 ] );
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 2 ] );
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 1 ] );
shiftOut( SOUT, SCLK, MSBFIRST, sig[ i + 0 ] );
// enable latch
digitalWrite( RCLK, HIGH );
// wait
delay( 275 );
}
}
//------------------------------------------------------------------------------
// upDown - moves a horizontal bar up and down the display
//------------------------------------------------------------------------------
void upDown( void )
{
byte i;
byte j;
for( i = 1 ; i < 8 ; i++ )
{
for( j = 0 ; j < 7 ; j++ )
{
out[ j ] = dot[ i ];
}
updateLeds();
delay( 152);
}
for( i = 6 ; i > 0 ; i-- )
{
for( j = 0 ; j < 7 ; j++)
{
out[ j ] = dot[ i ];
}
updateLeds();
delay( 152 );
}
}
//------------------------------------------------------------------------------
// updateLeds - shifts bits from out[] array to led shift registers
//------------------------------------------------------------------------------
inline void updateLeds( void )
{
// disable latch
digitalWrite( RCLK, LOW );
// move bytes to shift registers
shiftOut( SOUT, SCLK, MSBFIRST, out[ 6 ] );
shiftOut( SOUT, SCLK, MSBFIRST, out[ 5 ] );
shiftOut( SOUT, SCLK, MSBFIRST, out[ 4 ] );
shiftOut( SOUT, SCLK, MSBFIRST, out[ 3 ] );
shiftOut( SOUT, SCLK, MSBFIRST, out[ 2 ] );
shiftOut( SOUT, SCLK, MSBFIRST, out[ 1 ] );
shiftOut( SOUT, SCLK, MSBFIRST, out[ 0 ] );
// enable latch
digitalWrite( RCLK, HIGH );
}
//------------------------------------------------------------------------------
// readEq - reads analog values from the msgeq7 chip
//------------------------------------------------------------------------------
inline void readEq( void )
{
byte i;
// reset msgeq7 multiplexor
digitalWrite ( RESET, HIGH );
delayMicroseconds( 10 );
digitalWrite ( RESET, LOW );
digitalWrite ( STROBE, HIGH );
delayMicroseconds( 80 );
// read the eq values
for( i = 0 ; i < 7 ; i++ )
{
digitalWrite ( STROBE, LOW );
delayMicroseconds( 40 );
// lowpass the raw values
raw[ i ] = analogRead( EQ_DATA ) * 0.9 + raw[ i ] * 0.1;
digitalWrite ( STROBE, HIGH );
delayMicroseconds( 40 );
}
}
//------------------------------------------------------------------------------
// calculateValues - calculates spectrum values using data in raw[] array
//------------------------------------------------------------------------------
inline void calculateValues( void )
{
int i;
float x;
float minIn;
float maxIn;
// iterate through the raw bands
for( i = 0 ; i < 7 ; i++ )
{
// scale raw band value between 0 and 1
x = raw[ i ] / 1024.0;
// minimum averaging
//----------------------------------------------------------------------
// look at last three values
minPeak[ i ][ 2 ] = minPeak[ i ][ 1 ];
minPeak[ i ][ 1 ] = minPeak[ i ][ 0 ];
minPeak[ i ][ 0 ] = x;
// find valleys
if( ( minPeak[ i ][ 0 ] > minPeak[ i ][ 1 ] ) && ( minPeak[ i ][ 1 ] < minPeak[ i ][ 2 ] ) )
{
minIn = minPeak[ i ][ 1 ];
}
else
{
minIn = min[ i ];
}
// calculate weighted min average ( lowpass filter )
min[ i ] = min[ i ] * MIN_AVG_COEFF + minIn * minInCoeff;
// discard values below min
x -= min[ i ];
// normalize
x *= 1.0 / ( 1.0 - min[ i ] );
// clip between 0 and 1
x = clip( x, 0, 1 );
// maximum averaging
//----------------------------------------------------------------------
// look at last three values
maxPeak[ i ][ 2 ] = maxPeak[ i ][ 1 ];
maxPeak[ i ][ 1 ] = maxPeak[ i ][ 0 ];
maxPeak[ i ][ 0 ] = x;
// find peaks
if( ( maxPeak[ i ][ 0 ] < maxPeak[ i ][ 1 ] ) && ( maxPeak[ i ][ 1 ] > maxPeak[ i ][ 2 ] ) )
{
maxIn = maxPeak[ i ][ 1 ];
}
else
{
maxIn = max[ i ];
}
// update max peak average
max[ i ] = maxIn > max[ i ] ? maxIn : max[ i ];
// calculate weighted max average ( lowpass filter )
max[ i ] = max[ i ] * MAX_AVG_COEFF + maxIn * maxInCoeff;
// set minimum max average to MAX_THRESH
max[ i ] = max[ i ] < MAX_THRESH ? MAX_THRESH : max[ i ];
// normalize to average range
x /= max[ i ] - min[ i ];
// scaling
//----------------------------------------------------------------------
// drop values below threshold
x -= MIN_THRESH;
x *= 1.0 / ( 1.0 - MIN_THRESH );
// scale a little larger
x *= 1.2;
x -= MIN_THRESH;
// constrain between 0 and 1
x = clip( x, 0, 1 );
// output transfer function
x = xfer[ int( x * 99 ) ];
// update value for display
spec[ i ] = x > spec[ i ] ? x : spec[ i ];
}
// remap middle 5 input bands onto 7 output bands
band[ 0 ] = spec[ 1 ] * 0.950000 + spec[ 2 ] * 0.050000;
band[ 1 ] = spec[ 1 ] * 0.285714 + spec[ 2 ] * 0.714286;
band[ 2 ] = spec[ 2 ] * 0.714286 + spec[ 3 ] * 0.285714;
band[ 3 ] = spec[ 2 ] * 0.250000 + spec[ 3 ] * 0.500000 + spec[ 4 ] * 0.25;
band[ 4 ] = spec[ 3 ] * 0.285714 + spec[ 4 ] * 0.714286;
band[ 5 ] = spec[ 4 ] * 0.714286 + spec[ 5 ] * 0.285714;
band[ 6 ] = spec[ 5 ] * 0.900000 + spec[ 4 ] * 0.100000;
// create output values for display
for( i = 0 ; i < 7 ; i++ )
{
// constrain between 0 and 1
x = clip( band[ i ], 0, 1 );
// use remapped values for display
out[ i ] = dot[ ( int )( x * 8.0 ) ];
// update decay filter
spec[ i ] -= decayDec;
}
}
//------------------------------------------------------------------------------
// setMode - sets display mode based on index ( 1 - 4 )
//------------------------------------------------------------------------------
inline void setMode( byte index )
{
switch( mode )
{
// fast, bright
case 1 : decayDec = DECAY_FAST;
analogWrite( OE, BRIGHT );
break;
// fast, dim
case 2 : decayDec = DECAY_FAST;
analogWrite( OE, DIM );
break;
// slow, bright
case 3 : decayDec = DECAY_SLOW;
analogWrite( OE, BRIGHT );
break;
// slow, dim
case 4 : decayDec = DECAY_SLOW;
analogWrite( OE, DIM );
break;
}
}
//------------------------------------------------------------------------------
// numeral - displays a numeral based on value ( 1 - 4 )
//------------------------------------------------------------------------------
inline void numeral( byte value )
{
allOff();
value = value - 1;
out[ 6 ] = num[ 6 + value * 7 ];
out[ 5 ] = num[ 5 + value * 7 ];
out[ 4 ] = num[ 4 + value * 7 ];
out[ 3 ] = num[ 3 + value * 7 ];
out[ 2 ] = num[ 2 + value * 7 ];
out[ 1 ] = num[ 1 + value * 7 ];
out[ 0 ] = num[ 0 + value * 7 ];
updateLeds();
delay( 500 );
allOff();
}
//------------------------------------------------------------------------------
// allOff - turns off all leds
//------------------------------------------------------------------------------
inline void allOff( void )
{
byte i;
for( i = 0 ; i < 7 ; i++ )
{
out [ i ] = 0;
}
updateLeds();
}
//------------------------------------------------------------------------------
// setup - initializes arduino board
//------------------------------------------------------------------------------
void setup( void )
{
// disable leds
pinMode( OE, OUTPUT );
analogWrite( OE, 255 );
// configure pins
pinMode( SCLK, OUTPUT );
pinMode( RCLK, OUTPUT );
pinMode( SOUT, OUTPUT );
pinMode( OE, OUTPUT );
pinMode( STROBE, OUTPUT );
pinMode( RESET, OUTPUT );
pinMode( EQ_DATA, INPUT );
pinMode( MODE, INPUT );
// configure 5v analog reference for msgeq7
analogReference( DEFAULT );
// initialize variables
msec = 0;
nextMsec = 0;
swMode = 0;
swModePrev = 0;
swModeMsec = 0;
swModeState = 0;
maxInCoeff = 1.0 - MAX_AVG_COEFF;
minInCoeff = 1.0 - MIN_AVG_COEFF;
// read mode from memory
mode = EEPROM.read( EEPROM_MODE_ADDR );
// calculate transfer function
float x;
for( byte i = 0 ; i < 100 ; i++ )
{
x = float( i ) / 100.0;
xfer[ i ] = cos( 3.141592 * pow( x, 0.5 ) ) * -0.5 + 0.5;
}
// set mode
setMode( mode );
// initial display
allOff();
upDown();
signature();
}
//------------------------------------------------------------------------------
// loop - the main program loop
//------------------------------------------------------------------------------
void loop( void )
{
// read values from msgeq7
readEq();
// timer
//--------------------------------------------------------------------------
// store current millisecond value
msec = millis();
// spectrum
//--------------------------------------------------------------------------
// refresh spectrum if enough milliseconds have elapsed
if( ( long )( msec - nextMsec ) >= 0 )
{
// calculate next update time
nextMsec = msec + REFRESH_MSEC;
// update the spectrum
calculateValues();
updateLeds();
}
// switch
//--------------------------------------------------------------------------
// store switch state
swMode = digitalRead( MODE );
// if switch state has changed
if( swMode != swModePrev )
{
// store current millisecond value
swModeMsec = millis();
}
// if the debounce interval has elapsed
if( ( millis() - swModeMsec ) > DEBOUNCE_MSEC )
{
// if stitch state has changed
if( swMode != swModeState )
{
// store switch state
swModeState = swMode;
// if switch is on
if( swModeState == HIGH )
{
// increment and wrap mode value
mode++;
mode > 4 ? mode = 1 : mode;
// set the mode
setMode( mode );
// display the mode
numeral( mode );
// save mode value to memory
EEPROM.write( EEPROM_MODE_ADDR, mode );
}
}
}
// store swtich state
swModePrev = swMode;
}
//------------------------------------------------------------------------------
// EOF
//------------------------------------------------------------------------------